// Autor    : Marleen Neumann  

#include <windows.h>
#include <stdlib.h>
#include <glut.h>
#include <stdio.h>


#include <GL/gl.h>
#include <GL/glu.h>
#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>
#include <cstdio>
#include <iostream>


struct coordinate{
	float x, y, z; 
	coordinate(float a, float b, float c) : x(a), y(b), z(c) {}; 
}; 


struct face{
	int facenum; 
	bool four; 
	int faces[4]; 
	face(int facen, int f1, int f2, int f3) : facenum(facen){
		faces[0]=f1; 
		faces[1]=f2; 
		faces[2]=f3;
		four=false; 		
	}
	face(int facen, int f1, int f2, int f3, int f4): facenum(facen) {
		faces[0]=f1; 
		faces[1]=f2; 
		faces[2]=f3;
		faces[3]=f4;
		four=true; 
		
	}
}; 

//Rot Spotlight, Blau Punktlicht, Gruen Direktes Licht
//Blau
GLfloat LightSpeczwei[]= {1.0f,1.0f,1.0f,1.0f};
GLfloat LightPoszwei[]= {0.0f,1.0f,-1.0f,1.0f};
GLfloat LightDiffzwei[]= {0.0f,0.0f,1.0f,1.0f};

//Rot
float Direction[3] = {0.0f,0.0f,-1.0f};
GLfloat Ambientezwei[]= {0.0f,0.0f,0.0f,1.0f};
GLfloat LightSpec[]= {1.0f,1.0f,1.0f,1.0f};
GLfloat LightPos[]= {0.0f,0.0f,0.5f,1.0f};
GLfloat LightDiff[]= {1.0f,0.0f,0.0f,1.0f};

//Gruen
float Directionzwei[3] = {0.0f,0.0f,-1.0f};
GLfloat Ambientedrei[]= {0.0f,0.0f,0.0f,1.0f};
GLfloat LightSpecdrei[]= {1.0f,1.0f,1.0f,1.0f};
GLfloat LightPosdrei[]= {0.0f,0.0f,0.5f,1.0f};
GLfloat LightDiffdrei[]= {0.0f,1.0f,0.0f,0.0f};


float angle = 0.0; 

int loadObject(const char* filename)
{
	std::vector<std::string*> coord; 
	std::vector<coordinate*> vertex; 
	std::vector<face*> faces; 
	std::vector<coordinate*> normals; 
	std::ifstream in(filename); 
	if(!in.is_open())
	{
		std::cout << "Not open" << std::endl; 
		return -1; 
	}


	char buf[256]; 
	while(!in.eof())
	{
		in.getline(buf, 256); 
		coord.push_back(new  std::string(buf));
	}
	for(int i = 0; i < coord.size(); i++)
	{
		if((*coord[i])[0]=='#')
			continue; 
		else if((*coord[i])[0] =='v' && (*coord[i])[1] == ' ' )
		{			
			float tmpx, tmpy, tmpz; 
			sscanf(coord[i]->c_str(), "v %f %f %f",&tmpx, &tmpy, &tmpz); 
			vertex.push_back(new coordinate(tmpx, tmpy, tmpz)); 
			
		}
		else if((*coord[i])[0] =='v' && (*coord[i])[1] =='n' )
		{
			float tmpx, tmpy, tmpz;
			sscanf(coord[i]->c_str(), "vn %f %f %f",&tmpx, &tmpy, &tmpz);
			normals.push_back(new coordinate(tmpx, tmpy, tmpz)); 
			
		}else if((*coord[i])[0]=='f')
		{
			int a, b, c, d, e; 				
		
			if(count(coord[i]->begin(),coord[i]->end(),' ')==3)     
			{
					sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b);
					faces.push_back(new face(b,a,c,d));     
			}
			else
			{
					sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b,&e,&b);
					faces.push_back(new face(b,a,c,d,e));   
			}
			
		}

	}

	//Zeichnen

	int num;       
        num=glGenLists(1);      
        glNewList(num,GL_COMPILE);      
        for(int i=0;i<faces.size();i++)
        {
                if(faces[i]->four)     
                {
                        glBegin(GL_QUADS);                               
                                glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);                                
                                glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
                                glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
                                glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
                                glVertex3f(vertex[faces[i]->faces[3]-1]->x,vertex[faces[i]->faces[3]-1]->y,vertex[faces[i]->faces[3]-1]->z);																
                        glEnd();
                }else{
                        glBegin(GL_TRIANGLES);
                                glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
                                glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
                                glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
                                glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
                        glEnd();
                }
        }

	glEndList(); 

	for(int i=0; i<coord.size();i++)	
		delete coord[i];
	
	for(int i=0; i<faces.size(); i++)
		delete faces[i];

	for(int i=0; i<normals.size();i++)	
		delete normals[i];
	
	for(int i=0; i<vertex.size(); i++)
		delete vertex[i];

	return num; 
}




int cube; 


void init()
{
        glClearColor(0.0,0.0,0.0,1.0);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45,640.0/480.0,1.0,500.0);
        glMatrixMode(GL_MODELVIEW);
        glEnable(GL_DEPTH_TEST);
        cube=loadObject("link.obj");    
        glEnable(GL_LIGHTING);  
        glEnable(GL_LIGHT0);
        float col[]={0.0,1.0,0.0,1.0};  
        glLightfv(GL_LIGHT0,GL_DIFFUSE,col);


		glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpec);
		glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
		glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiff);
		

		glLightfv(GL_LIGHT1, GL_AMBIENT, Ambientedrei);
		glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpeczwei);
		glLightfv(GL_LIGHT1, GL_POSITION, LightPoszwei);
		glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffzwei);
		
	

		glLighti(GL_LIGHT2, GL_SPOT_CUTOFF, 20);
		glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, Directionzwei);
		glLightfv(GL_LIGHT2, GL_AMBIENT, Ambientedrei);
		glLightfv(GL_LIGHT2, GL_SPECULAR, LightSpecdrei);
		glLightfv(GL_LIGHT2, GL_POSITION, LightPosdrei);
		glLightfv(GL_LIGHT2, GL_DIFFUSE, LightDiffdrei);
		

		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		glEnable(GL_LIGHT1);
		glEnable(GL_LIGHT2);
}

void display()
{
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        float pos[]={-1.0,1.0,-2.0,1.0};        
        glLightfv(GL_LIGHT0,GL_POSITION,pos);
        glTranslatef(0.0,-3.0,-5.0);
        glRotatef(angle,0.0,1.0,0.0);
        glCallList(cube);      

		glFlush();
}


void reshape (int w, int h)
{
   
   glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
   glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
   glMatrixMode (GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:
         exit(0);
         break;
   }
}

void idle( void )
{
	angle+= 0.01f;
	glutPostRedisplay();
}



int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);  
   glutInitWindowSize (500, 500); 
   glutInitWindowPosition (100, 100);
   glutCreateWindow (argv[0]);
   init ();   
   glutDisplayFunc(display); 
   glutIdleFunc( idle );
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);
   glutMainLoop();
   return 0;
}
